package org.mindrive.system.service.system;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.mindrive.system.annotation.LogOperation;
import org.mindrive.system.collection.system.LogEntity;
import org.mindrive.system.collection.system.UserEntity;
import org.mindrive.system.core.MindriveException;
import org.mindrive.system.dao.LogDao;
import org.mindrive.system.entity.OptionEntity;
import org.mindrive.system.parameter.system.SearchLogParameter;
import org.mindrive.system.service.BaseService;
import org.mindrive.system.util.ConvertUtil;
import org.mindrive.system.util.DateTimeUtil;
import org.mindrive.system.util.IPUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.text.ParseException;
import java.util.*;

@Service
@Slf4j
public class LogService extends BaseService {

    @Autowired
    public LogDao logDao;


    public void saveEvent(JoinPoint joinPoint, Object res, long time) {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        LogEntity audit = new LogEntity();
        LogOperation auditEvent = method.getAnnotation(LogOperation.class);

        String event = "";
        if (auditEvent != null && auditEvent.event() != null && !"".equals(auditEvent.event())) {
            event = auditEvent.event();
        } else {
            event = signature.getName();
        }
        audit.setCostTime(BigInteger.valueOf(time));
        // 请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        audit.setRequestMethod(className + "." + method.getName() + "()");
        audit.setEvent(event);
        audit.setEventType(auditEvent.type());

        // 获取request
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 设置IP地址
        audit.setIp(IPUtil.getIpAddr(request));
        audit.setUrl(request.getRequestURL().toString());
        audit.setRequestType(request.getMethod());
        audit.setCreatedAt(new Date());

        UserEntity loginUser = getLoginUser();
        audit.setUserId(loginUser.getId());
        audit.setUserName(loginUser.getUserName());

        // 请求的参数
        Object[] args = joinPoint.getArgs();
        List<Object> newArgs = new ArrayList<Object>();

        if (args != null && args.length != 0) {
            for (Object obj : args) {
                if (obj instanceof MultipartFile) {

                } else if (obj instanceof MultipartFile[]) {

                } else if (obj instanceof BindingResult) {

                } else if (obj instanceof HttpServletResponse) {

                } else if (obj instanceof HttpServletRequest) {

                } else {
                    newArgs.add(obj);
                }
            }
        }
        try {
            String parameterString = JSON.toJSONString(newArgs);
            audit.setRequestParameter(parameterString);
        } catch (Exception e) {
            log.error("请求参数转换成JSON失败", e);
        }
        logDao.save(audit);
    }

    public Map<String, Object> searchAuditOperations(SearchLogParameter parameter) throws ParseException {
        log.debug("操作日志查询");
        Date beginTimeDate = null;
        Date endTimeDate = null;

        if (!"".equals(parameter.getBeginTime()) && parameter.getBeginTime() != null) {
            try {
                beginTimeDate = DateTimeUtil.getStartTime(parameter.getBeginTime());
            } catch (ParseException e) {
                log.error("解析时间失败。", e);
            }
        } else {
            beginTimeDate = DateTimeUtil.getStartTime(DateTimeUtil.getDateBefore(new Date(), 90));
        }

        if (!"".equals(parameter.getEndTime())) {
            try {
                endTimeDate = DateTimeUtil.getEndTime(parameter.getEndTime());
            } catch (ParseException e) {
                log.error("解析时间失败。", e);
            }
        } else {
            endTimeDate = DateTimeUtil.getEndTime(new Date());
        }
//		if (DateTimeUtil.getDaysOfTwoDate(beginTimeDate, endTimeDate) > 30) {
//			throw new MindriveException("只能查询从开始时间开始，30天以内的数据");
//		}
        long d1 = DateTimeUtil.getEndTime(endTimeDate).getTime();
        long d2 = DateTimeUtil.getStartTime(DateTimeUtil.getDateAfter(new Date(), 1)).getTime();
        if (d1 > d2) {
            throw new MindriveException("结束时间不能大于当前时间");
        }
        if (endTimeDate.before(beginTimeDate)) {
            throw new MindriveException("开始时间不能大于结束时间");
        }
        int count = 0;
        List<Map> list = new ArrayList<>();
        Map<String, Object> data = new HashMap<String, Object>();
        if (!"".equals(parameter.getLogDataTime()) && parameter.getLogDataTime() != null) {

            String logTableName = parameter.getLogDataTime();

            //设置参数 根据表的tableName查 事件、用户id、开始时间、结束时间、操作类型。
            Map<String, Object> tableParameter = new HashMap<String, Object>();
            tableParameter.put("tableName", logTableName);
            tableParameter.put("name", parameter.getName());
            tableParameter.put("userId", parameter.getUserId());
            tableParameter.put("beginTimeDate", beginTimeDate);
            tableParameter.put("endTimeDate", endTimeDate);
            tableParameter.put("eventType", parameter.getEventType());
            tableParameter.put("curPage", parameter.getCurrentPage());
            tableParameter.put("pageSize", parameter.getPageSize());
            count = logDao.selectLogHistoryCount(tableParameter);
            list = logDao.selectLogHistory(tableParameter);


            data.put(COUNT, count);
            data.put(LIST, list);

        } else {
            Map<String, Object> tableParameter = new HashMap<String, Object>();
            tableParameter.put("tableName", "hadoop_logs");
            tableParameter.put("name", parameter.getName());
            tableParameter.put("userId", parameter.getUserId());
            tableParameter.put("beginTimeDate", beginTimeDate);
            tableParameter.put("endTimeDate", endTimeDate);
            tableParameter.put("eventType", parameter.getEventType());
            tableParameter.put("curPage", parameter.getCurrentPage());
            tableParameter.put("pageSize", parameter.getPageSize());
            count = logDao.selectLogHistoryCount(tableParameter);
            list = logDao.selectLogHistory(tableParameter);


            data.put(COUNT, count);
            data.put(LIST, list);

        }

        return data;
    }

    public List<OptionEntity> getAuditEventTypes() {
        List<OptionEntity> list = new ArrayList<OptionEntity>();
        list.add(OptionEntity.add(AUDIT_EVENT_TYPE_CREATE, AUDIT_EVENT_TYPE_CREATE));
        list.add(OptionEntity.add(AUDIT_EVENT_TYPE_DELETE, AUDIT_EVENT_TYPE_DELETE));
        list.add(OptionEntity.add(AUDIT_EVENT_TYPE_MODIFY, AUDIT_EVENT_TYPE_MODIFY));
        list.add(OptionEntity.add(AUDIT_EVENT_TYPE_SEARCH, AUDIT_EVENT_TYPE_SEARCH));
        list.add(OptionEntity.add(AUDIT_EVENT_TYPE_IMPORT, AUDIT_EVENT_TYPE_IMPORT));
        list.add(OptionEntity.add(AUDIT_EVENT_TYPE_EXPORT, AUDIT_EVENT_TYPE_EXPORT));
        return list;
    }

    public Map<String, Object> detail(String auditId) {
        LogEntity audit = logDao.getById(auditId);
        Map<String, Object> map = ConvertUtil.entityToMap(audit);
        return map;
    }


}
